package guggaTests.tasks
{
	import flash.events.Event;
	
	import flexunit.framework.TestCase;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.tasks.CustomCompleteTask;
	import gugga.tasks.ExecuteAsyncMethodTask;
	import gugga.tasks.FictiveTask;
	import gugga.tasks.IProgressiveTask;
	import gugga.tasks.ITask;
	import gugga.tasks.ProgressiveTaskDecorator;
	import gugga.tasks.events.TaskEvent;
	import gugga.tasks.events.ProgressiveTaskEvent;
	import flash.utils.Timer;
	import flash.events.TimerEvent;

	public class ProgressiveTaskDecoratorTest extends TestCase
	{
		private static const FAKE_PROGRESS_DISPATCH_PERCENTS : Number = 20;
		
		private var mProgressiveTaskDecorator : ProgressiveTaskDecorator;
		private var mFictiveTask : FictiveTask;
		private var mCustomCompleteTask : CustomCompleteTask;
		
		private var mTask : ITask;
		
		private var mIsTaskStarted : Boolean;
		private var mIsTaskCompleted : Boolean;
		
		private var mProgress : Number;
		public function ProgressiveTaskDecoratorTest(methodName:String=null)
		{
			super(methodName);
		}
		
		public override function setUp() : void
		{
			mIsTaskStarted = false;
			mIsTaskCompleted = false;
			mProgress = 0;
		}
		
		public function testConstructor() : void 
		{
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(new FictiveTask());
			
			assertNotNull("mProgressiveTaskDecorator should not be null after creation", mProgressiveTaskDecorator);
			assertNotUndefined("mProgressiveTaskDecorator should not be undefined after creation", mProgressiveTaskDecorator);			
		}
		
		public function testWrappedTask() : void
		{
			var wrappedTask : FictiveTask = new FictiveTask();
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(wrappedTask);
			
			assertEquals("mProgressiveTaskDecorator.WrappedTask should be equeal to wrapped task",
				wrappedTask,
				mProgressiveTaskDecorator.WrappedTask);
		}
		
		public function testStartAndCompletionWithExecuteAsyncMethodTask() : void
		{
			mFictiveTask = new FictiveTask();
			var eventDescriptor : EventDescriptor = new EventDescriptor(mFictiveTask, TaskEvent.START);
			var asyncTask : ExecuteAsyncMethodTask 
				= ExecuteAsyncMethodTask.create(eventDescriptor, emptyMethod, []);
				
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(asyncTask);
			
			mProgressiveTaskDecorator.addEventListener(TaskEvent.START, onTaskStart);
			mProgressiveTaskDecorator.addEventListener(TaskEvent.COMPLETED, onTaskCompleted);
			mProgressiveTaskDecorator.addEventListener(TaskEvent.COMPLETED, 
				addAsync(assertProgressiveTaskDecoratorCompleted, 300));
				
			mProgressiveTaskDecorator.start();
			
			assertTrue("mProgressiveTaskDecorator should be started", mIsTaskStarted);
			
			mFictiveTask.start();
		}
		
		private function assertProgressiveTaskDecoratorCompleted(aEvent : TaskEvent) : void
		{
			var progressiveTask : IProgressiveTask = IProgressiveTask(aEvent.target);
			
			assertFalse("Progressive task should not be running", progressiveTask.isRunning());
			
			assertTrue("Progressive task should be completed", mIsTaskCompleted);
		}
		
		public function testStartAndCompleteWithCustomCompleteTask() : void
		{
			mCustomCompleteTask = new CustomCompleteTask();
			
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(mCustomCompleteTask);
			
			mProgressiveTaskDecorator.addEventListener(TaskEvent.START, onTaskStart);
			mProgressiveTaskDecorator.addEventListener(TaskEvent.COMPLETED, onTaskCompleted);
			mProgressiveTaskDecorator.addEventListener(TaskEvent.COMPLETED, addAsync(assertTaskCompleted, 300));
			
			mProgressiveTaskDecorator.start();
			
			assertTrue("Task should be started", mIsTaskStarted);
			
			mCustomCompleteTask.complete();
		}
		
		private function assertTaskCompleted(aEvent : Event) : void
		{
			var task : ITask = ITask(aEvent.target);
			
			assertTrue("Task should be completed", mIsTaskCompleted);
			assertFalse("Task should not be running", task.isRunning());		
		}
		
		public function testIsImmediatelyInterruptable() : void
		{
			mTask = new FictiveTask();
			
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(mTask);
			
			assertEquals("mTask.isImmediatelyInterruptable should be equal to mProgressiveTaskDecorator.isImmediatelyInterruptable", 
				mTask.isImmediatelyInterruptable(),
				mProgressiveTaskDecorator.isImmediatelyInterruptable());
		}
		
		public function testInterrupt() : void
		{
			mFictiveTask = new FictiveTask();
			
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(mFictiveTask);
			
			mProgressiveTaskDecorator.addEventListener(TaskEvent.START, onTaskStart);
			mProgressiveTaskDecorator.addEventListener(TaskEvent.INTERRUPTED, addAsync(assertProgressiveTaskDecoratorInterrupted, 300));
			
			mProgressiveTaskDecorator.start();
			
			assertTrue("Task should be started", mIsTaskStarted);
			
			mProgressiveTaskDecorator.interrupt();			
		}
		
		private function assertProgressiveTaskDecoratorInterrupted(aEvent : Event) : void
		{
			var task : ITask = ITask(aEvent.target);
			
			assertFalse("Task should be interrupted", task.isRunning());
		}
		
		public function testProgress() : void
		{
			var timer : Timer = new Timer(100, 1);
			
			mFictiveTask = new FictiveTask();
			mProgressiveTaskDecorator = new ProgressiveTaskDecorator(mFictiveTask);
			
			mProgressiveTaskDecorator.addEventListener(ProgressiveTaskEvent.PROGRESS, onTaskProgress);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE, addAsync(assertProgressiveTaskDecoratorProgress, 200));
						
			mProgressiveTaskDecorator.FakeProgressDispatchPercents = FAKE_PROGRESS_DISPATCH_PERCENTS;
			mProgressiveTaskDecorator.FakeProgressDispatchInterval = 10;
			
			mProgressiveTaskDecorator.startProgressing();
			timer.start();	
		}
		
		private function assertProgressiveTaskDecoratorProgress(aEvent : Event) : void
		{
			assertEquals("Unexpected progress value", mProgressiveTaskDecorator.getProgress(), mProgress + FAKE_PROGRESS_DISPATCH_PERCENTS);
		}
		
		private function onTaskProgress(aEvent : ProgressiveTaskEvent) : void
		{
			mProgress = aEvent.Current;
		}
		
		private function onTaskStart(aEvent : Event) : void
		{
			mIsTaskStarted = true;
		}
		
		private function onTaskCompleted(aEvent : Event) : void
		{
			mIsTaskCompleted = true;
		}
		
		private function emptyMethod() : void
		{
			//THIS METHOD SHOULD ALWAYS BE EMPTY
		}
	}
}